/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#ifndef PROPERTY_BAG
#define PROPERTY_BAG

#include <map>
#include <vector>
#include "object.h"
#include "property.h"

using namespace std;

/*
typedef enum {
  PROPERTY_UNKNOWN, // 0
  PROPERTY_BOOL,    // 1 bool
  PROPERTY_INT,     // 2 int
  PROPERTY_FLOAT,   // 3 float
  PROPERTY_SIGNED,  // 4 signed
  PROPERTY_VEC2,            // 5
  PROPERTY_VEC3,            // 6
  PROPERTY_STRING,					// 7 string
  PROPERTY_ORDINAL,				// 8 also a string
  PROPERTY_SELECTION,       // 9
  PROPERTY_MULTISELECTION   // 10
} PropType;

struct Interval {
	float start, end;
	Interval(float a, float b) {
		start = a;
		end = b;
	}
};
*/

const int NUM_TYPES = 11;
class PropertyBag;
class PropertyParser {
public:
	virtual void parse(string name, void* value) = 0;
	virtual string format(PropertyBag*bag, string name) = 0;
	virtual void parse(PropertyBag*bag, string name, string value) = 0;
};

typedef struct {
	float v[2];
	float &operator[](int i) {
		return v[i];
	}
} vec2;
class PropertyBag: public Object {
 protected:
	map<string, int> intProperties;
	map<string, float> floatProperties;
	map<string, bool> boolProperties;
	map<string, string> stringProperties;
	map<string, vec2> vec2Properties;
	map<string, int> types;
	map<string, string> models;

 public:
	
	static::PropertyParser* parsers[NUM_TYPES];
	static string format(int type, PropertyBag *bag, string name);
	static void parse(int type, PropertyBag *bag, string name, string value);
	
	
  PropertyBag(const char*type, const char *name);
  virtual ~PropertyBag();
  vector<string> getProperties();
  bool hasProperty(string name);
	
	
	inline void addProperty(string name, int type, string value, string model="") {
		PropertyBag::parse(type, this, name, value);
		if(model!="") setModel(name, model);
	}
  
	inline void setProperty(string name, string value) {
		int type = types[name];
		PropertyBag::parse(type, this, name, value);
	}

	inline void setModel(string name, string model) {
		models[name] = model;
	}
	
  inline void setPropertyString(string name, string s) {
		stringProperties[name] = s;
		if(types.find(name)==types.end()) { 
			types[name] = PROPERTY_STRING;
		}
	}
  inline void setPropertyString(string name, const char * s) {
		stringProperties[name] = string(s);
		if(types.find(name)==types.end()) { 
			types[name] = PROPERTY_STRING;
		}
	}
  inline void setPropertyStringList(string name, string s, string model = "none", bool multi=false) {
		stringProperties[name] = s;
		types[name] = (multi)? PROPERTY_MULTISELECTION:PROPERTY_SELECTION;
		models[name] = string(model);
	}
  inline void setPropertyStringList(string name, const char * s, const char * model = 0, bool multi=false) {
		stringProperties[name] = string(s);
		types[name] = (multi)? PROPERTY_MULTISELECTION:PROPERTY_SELECTION;
		models[name] = string(model);
	}
  inline void setPropertyOrdinal(string name, string s, string model) {
		stringProperties[name] = s;
		types[name] = PROPERTY_ORDINAL;
		models[name] = string(model);
	}
	
  inline string getPropertyString(string name) {
		return stringProperties[name];
	}
	inline void parseString(string name, string value) {
		int type = types[name];
		PropertyBag::parse(type, this, name, value);
	}
	
	inline string getAsString(string name) {
		if(types.find(name)==types.end()) return "";
		int type = types[name];
		return PropertyBag::format(type, this, name);
	}
		
  inline void setPropertyFloat(string name, float v) {
		floatProperties[name] = v;
		types[name] = PROPERTY_FLOAT;
	}	
  inline void setPropertySigned(string name, float v) {
		floatProperties[name] = v;
		types[name] = PROPERTY_SIGNED;
	}	
  inline float getPropertyFloat(string name, float defaultValue = 0.0) {
		return floatProperties[name];
	}
	
  inline void setPropertyInt(string name, int v) {
		intProperties[name] = v;
		types[name] = PROPERTY_INT;
	}	
  inline int getPropertyInt(string name, int defaultValue = 0) {
		return intProperties[name];
	}
	
  inline void setPropertyBool(string name, bool v) {
		boolProperties[name] = v;
		types[name] = PROPERTY_BOOL;
	}
  inline bool getPropertyBool(string name, bool defaultValue = false) {
		return boolProperties[name];
	}
	
  inline void setPropertyVec2(string name, float x, float y) {
		vec2Properties[name][0] = x;
		vec2Properties[name][1] = y;
		types[name] = PROPERTY_VEC2;
	}
  inline void setPropertyVec2v(string name, float *v) {
		vec2Properties[name][0] = v[0];
		vec2Properties[name][1] = v[1];
		types[name] = PROPERTY_VEC2;
	}
  inline void getPropertyVec2(string name, float *v) {
		v[0] = vec2Properties[name][0];
		v[1] = vec2Properties[name][1];
	}
	
  void setPropertyVec3(string name, float x, float y, float z);
  void setPropertyVec3v(string name, float *v);
  void getPropertyVec3(string name, float *v);

  inline int getPropertyType(string name) {
		if(types.find(name)==types.end()) { 
			return PROPERTY_UNKNOWN;
		} 
		return types[name];
	}
  inline string getPropertyListModel(string name) {
		if(models.find(name)==models.end()) { 
			return "";
		}
		return models[name];
	}
 
};




#endif
